All files / src/app/api/admin/support/tickets/[id]/assign route.ts

0% Statements 0/138
100% Branches 0/0
0% Functions 0/1
0% Lines 0/138

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139                                                                                                                                                                                                                                                                                     
export const dynamic = "force-dynamic";

/**
 * Admin Ticket Assignment API
 * POST /api/admin/support/tickets/[id]/assign - Assign ticket to agent
 */

import { NextRequest, NextResponse } from 'next/server';
import { requireAdminRole, handleAuthError } from '@/lib/auth';
import { prisma } from '@/lib/prisma';
import { AssignTicketSchema } from '@/lib/validation/support-schemas';
import { recordAssignment } from '@/lib/support/ticket-utils';
import { notifyAgentAssigned } from '@/lib/support/notification-utils';
import { TicketStatus, SupportTicketWithRelations } from '@/types/support';
import { handleError } from '@/lib/error-handler';
import { logger } from '@/lib/logging';

interface RouteParams {
  params: Promise<{ id: string }>;
}

export async function POST(request: NextRequest, { params }: RouteParams) {
  try {
    const session = await requireAdminRole();
    const { id } = await params;
    const adminId = Number(session.user.id);

    // Get current ticket
    const ticket = await prisma.supportTicket.findUnique({
      where: { id },
      select: {
        id: true,
        ticketNumber: true,
        assignedToId: true,
        status: true}});

    if (!ticket) {
      return NextResponse.json(
        { success: false, error: 'Ticket not found' },
        { status: 404 }
      );
    }

    // Validate input
    const body = await request.json();
    const validationResult = AssignTicketSchema.safeParse(body);
    if (!validationResult.success) {
      return NextResponse.json(
        {
          success: false,
          error: 'Validation failed',
          details: validationResult.error.flatten().fieldErrors},
        { status: 400 }
      );
    }

    const { assignedToId } = validationResult.data;

    // Verify the agent exists and is an admin
    if (assignedToId) {
      const agent = await prisma.user.findUnique({
        where: { id: assignedToId },
        select: { id: true, role: true }});

      if (!agent || agent.role !== 'ADMIN') {
        return NextResponse.json(
          { success: false, error: 'Invalid agent' },
          { status: 400 }
        );
      }
    }

    // Build update data
    const updateData: Record<string, unknown> = {
      assignedToId};

    // If assigning and ticket is OPEN, move to IN_PROGRESS
    if (assignedToId && ticket.status === TicketStatus.OPEN) {
      updateData.status = TicketStatus.IN_PROGRESS;
    }

    // Set first response time if this is the first assignment
    if (assignedToId && !ticket.assignedToId) {
      updateData.firstResponseAt = new Date();
    }

    // Update the ticket
    const updatedTicket = await prisma.supportTicket.update({
      where: { id },
      data: updateData,
      include: {
        user: {
          select: { id: true, name: true, email: true }},
        assignedTo: {
          select: { id: true, name: true, email: true }}}});

    // Record in history
    await recordAssignment(id, ticket.assignedToId, assignedToId, adminId);

    // Notify new agent
    if (assignedToId) {
      await notifyAgentAssigned(
        updatedTicket as unknown as SupportTicketWithRelations,
        assignedToId
      );

      // Update agent profile stats
      await prisma.supportAgentProfile.upsert({
        where: { userId: assignedToId },
        update: {
          totalTickets: { increment: 1 }},
        create: {
          userId: assignedToId,
          totalTickets: 1}});
    }

    logger.info('Ticket assigned', {
      category: 'ADMIN_SUPPORT',
      ticketId: id,
      ticketNumber: ticket.ticketNumber,
      oldAssignee: ticket.assignedToId,
      newAssignee: assignedToId,
      adminId});

    return NextResponse.json({
      success: true,
      data: updatedTicket,
      message: assignedToId
        ? `Ticket assigned to ${updatedTicket.assignedTo?.name || 'agent'}`
        : 'Ticket unassigned'});
  } catch (error) {
    const authResponse = handleAuthError(error as Error);
    if (authResponse) return authResponse;

    logger.error('Error assigning ticket', error instanceof Error ? error : new Error(String(error)), { category: 'ADMIN_SUPPORT' });
    return handleError(error);
  }
}